package com.carryking.smart.rpc.spring;

import com.carryking.smart.rpc.discover.DiscoverService;
import com.carryking.smart.rpc.discover.DiscoverServiceFactory;
import com.carryking.smart.rpc.entity.DiscoverConfigEntity;
import com.carryking.smart.rpc.netty.ProviderChannelInitializer;
import com.carryking.smart.rpc.utils.ServerInvokUtils;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;

import java.util.HashMap;
import java.util.Map;

/**
 * Created by jincarry on 2018/1/11.
 */
@Slf4j
public class ServiceSpringInitListener implements ApplicationListener<ContextRefreshedEvent> {

    private static final EventLoopGroup workGroup = new NioEventLoopGroup();

    private static final EventLoopGroup boosGroup = new NioEventLoopGroup();

    public void onApplicationEvent(final ContextRefreshedEvent contextRefreshedEvent) {

        final DiscoverConfigEntity configEntity = contextRefreshedEvent.getApplicationContext().getBean(DiscoverConfigEntity.class);

        //初始化application context
        ServerInvokUtils.setContext(contextRefreshedEvent.getApplicationContext());
        //初始化服务中心
        proccessDiscoverService(contextRefreshedEvent.getApplicationContext(),configEntity);

        new Thread(new Runnable() {
            public void run() {
                final int port = configEntity.getPort();
                ServerBootstrap bootstrap = new ServerBootstrap();
                bootstrap.group(workGroup, boosGroup)
                        .channel(NioServerSocketChannel.class)
                        .option(ChannelOption.SO_BACKLOG, 100)
                        .childHandler(new ProviderChannelInitializer());

                ChannelFuture f;
                try {
                    f = bootstrap.bind(port).sync().addListener(new GenericFutureListener(){
                        public void operationComplete(Future future) throws Exception {
                            log.info("Rpc服务启动成功;port={}",port);
                        }
                    });

                    f.channel().closeFuture().sync();
                } catch (InterruptedException e) {
                    log.info("Rpc服务启动发生异常",e);
                } finally {
                    workGroup.shutdownGracefully();
                    boosGroup.shutdownGracefully();
                    log.info("服务启动");
                }
            }
        }).start();


        new Thread(new Runnable() {
            public void run() {
                ApplicationContext context = contextRefreshedEvent.getApplicationContext();
                DiscoverService discoverService = DiscoverServiceFactory.build();
                String[] services = context.getBeanNamesForAnnotation(RpcService.class);
                for (String serverName : services) {
                    Object serverImpl = context.getBean(serverName);
                    discoverService.regisService(serverImpl.getClass().getInterfaces()[0].getSimpleName());
                    if (log.isDebugEnabled()) {
                        log.debug("注册服务到服务中心:serviceName={}",serverImpl.getClass().getInterfaces()[0].getSimpleName());
                    }
                }

            }
        }).start();
    }

    public static void close() {
        if (workGroup != null) {
            workGroup.shutdownGracefully();
        }
        if (boosGroup != null) {
            boosGroup.shutdownGracefully();
        }
    }

    private void proccessDiscoverService(ApplicationContext context, DiscoverConfigEntity configEntity) {
        DiscoverServiceFactory.init(configEntity);
    }
}
